from cProfile import Profile
from datetime import timedelta, datetime
from functools import wraps
from pstats import Stats
from time import time_ns


def profiling(do: bool = True, output: str | None = None, print_out: bool = False, sort_by: str = 'cumtime',
              interval_call: int = 1000, slow_call: bool = False, slow_call_threshold: int = 1):
    def wrapper(func):
        call_count = 0
        pr = Profile()

        @wraps(func)
        def wrapped(*args, **kwargs):
            nonlocal call_count

            if not do:
                return func(*args, **kwargs)
            with pr:
                start = time_ns()
                ret = func(*args, **kwargs)
                end = time_ns()

            # 统计最大运行时间
            elapsed = end - start
            if slow_call and timedelta(milliseconds=elapsed / 100_0000).total_seconds() > slow_call_threshold:
                print(f'{datetime.now().isoformat()} slow call:{func.__name__} elapsed: {timedelta(milliseconds=elapsed / 1000000)}')

            if (call_count := call_count + 1) > interval_call:
                call_count = 0

                if output:
                    Stats(pr).sort_stats(sort_by).dump_stats(output)
                if print_out:
                    Stats(pr).sort_stats(sort_by).print_stats()

            return ret

        return wrapped

    return wrapper
